package org.jivesoftware.launcher;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.jar.JarOutputStream;
import java.util.jar.Pack200;

public class Startup
{
	private static final String DEFAULT_LIB_DIR = "../lib";
	
	public static void main(String[] args)
	{
		new Startup().start(args);
	}
	
	private void start(String[] args)
	{
		try
		{
			final ClassLoader parent = findParentClassLoader();
			
			File libDir;
			final String workingDirectory = System.getProperty("appdir");
			if (workingDirectory == null)
			{
				libDir = new File(DEFAULT_LIB_DIR);
			}
			else
			{
				libDir = new File(new File(workingDirectory), "lib");
			}
			
			File pluginDir = new File(libDir.getParentFile(), "plugins");
			
			unpackArchives(libDir, true);
			
			unpackArchives(pluginDir, true);
			
			final ClassLoader loader = new JiveClassLoader(parent, libDir);
			
			Thread.currentThread().setContextClassLoader(loader);
			
			Class sparkClass = loader.loadClass("org.jivesoftware.Spark");
			Object instanceOfSpark = sparkClass.newInstance();
			
			if (args.length > 0)
			{
				String argument = args[0];
				Method setArgument = sparkClass.getMethod("setArgument", String.Class);
				setArgument.invoke(instanceOfSpark, argument);
			}
			
			Method startupMethod = sparkClass.getMethod("startup");
			startupMethod.invoke(instanceOfSpark);
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
	
	private ClassLoader findParentClassLoader()
	{
		ClassLoader parent = Thread.currentThread().getContextClassLoader();
		if (parent == null)
		{
			parent = this.getClass().getClassLoader();
			if (parent == null)
			{
				parent = ClassLoader.getSystemClassLoader();
			}
		}
		return parent;
	}
	
	private void unpackArchives(File libDir, boolean printStatus)
	{
		File[] packedFiles = libDir.listFiles(new FilenameFilter()
		{
			public boolean accept(File dir, String name)
			{
				return name.endsWith(".pack");
			}
		});
		
		if (packedFiles == null)
		{
			return;
		}
		
		boolean unpacked = false;
		for (File packedFile : packedFiles)
		{
			try
			{
				String jarName = packedFile.getName().substring(0,
					packedFile.getName().length() - ".pack".length());
				File jarFile = new File(libDir, jarName);
				if (jarFile.exists())
				{
					jarFile.delete();
				}
				
				InputStream in = new BufferedInputStream(new FileInputStream(packedFile));
				JarOutputStream out = new JarOutputStream(new BufferedOutputStream(
					new FileOutputStream(new File(libDir, jarName))));
				Pack200.Unpacker unpacker = Pack200.newUnpacker();
				if (printStatus)
				{
					System.out.print(".");
				}
				unpacker.unpack(in, out);
				
				in.close();
				out.close();
				packedFile.delete();
				unpacked = true;
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
		}
		if (unpacked && printStatus)
		{
			System.out.println();
		}
	}
}
